Mittwoch, 28. Oktober 2015

AppleScript to quickly change your dns setting

Here ist a neat little applescript to quickly change your DNS settings.
Useful when you often have to switch between your routers DNS and for example Unblock-Us.


set dnsList to {"Unblock US", "Default"}
set selectedDNS to {choose from list dnsList with title "DNS Server to set"}

display dialog "Admin Password to change network settings" default answer ""
set pw to text returned of result

log item 1 of selectedDNS
log "test"

if item 1 of selectedDNS is {"Unblock Us"} then
 log "Unblock US"
 do shell script "networksetup -setdnsservers Wi-Fi 208.122.23.23" user name "fred" password pw with administrator privileges
else if item 1 of selectedDNS is {"Default"} then
 log "Default DNS"
 do shell script "networksetup -setdnsservers Wi-Fi 192.168.1.1" user name "fred" password pw with administrator privileges
else
 log "Got no valid value"
end if

Dienstag, 25. August 2015

Find and delete files older than X days (Linux Shell)

From time to time I need to clean certain folders from log files.

Here is a handy command that deletes files

  • in current folder 
  • that are older than 2 days
  • and that have the extension .log 


 find . -type f -mtime +2 -name '*.log' -exec rm {} \;

Freitag, 6. Februar 2015

Apple script to connect to AFP network shares with password prompt

I have Synology NAS and thus connect several folders as network shares.
Since the connection often gets lost, especially after the Mac is going to sleep I wrote a little script.
The script prompts for password so you don't have to expose it.
Enjoy ;)


display dialog "Password to connect to NAS" default answer ""
set nas_pw to text returned of result
try
mount volume "afp://username:" & nas_pw & "@nas_ip_or_dns/photo"
mount volume "afp://username:" & nas_pw & "@nas_ip_or_dns/home"
mount volume "afp://username:" & nas_pw & "@nas_ip_or_dns/music"
mount volume "afp://username:" & nas_pw & "@nas_ip_or_dns/video"
mount volume "afp://username:" & nas_pw & "@nas_ip_or_dns/share"
end try

Sonntag, 10. August 2014

Google AppEngine and GoDaddy SSL certificate - renewal process

I just had to renew my AppEngine SSL certificate and as always I totally forogt how I did it the last time.

So here are steps. Maybe they prove helpful for someone else. :)


  1. First create a CSR (certificate signing request). Since I already had one for creating the certificate in the first place I reused it. Fire up Google if you need to know how it is done.
  2. Log into your GoDaddy account and follow the steps for the renewal.
  3. Be sure to select deployment on an external server! Otherwise GoDaddy uses it for there hosted products and you can't download it. 
  4. Download the certificate. It is a zip containing 2 files. Your certifcate and the certificate chain (something like gd_bundle-g2-g1.crt)
  5. Now here comes the most important part. The Google Management console always complaint that I need to upload the private key and the crt in unencrypted pem/x509 format. You have to combine the two files via
    1. cat YOUR_CERT.crt GODADDY_CERT_CHAIN.crt > your-crt-combined.pem
  6. After that upload this file together with your private key and you're good to go.

One last note: The SSL configuration doesn't take place in AppEngine settings but inside your Google Apps account.


Samstag, 12. Juli 2014

Quickly see changed files between two git branches

To only see all files with changes between two branches just use

git diff branch1...branch2 --name-status <Path (optional)>

Mittwoch, 24. Oktober 2012

Sencha Touch 2 - Simple Localization (i10n)

When I started writing my Sencha Touch 2 App I didn't find a suitable localization solution build into it. Also I didn't want to include another JS library for doing this job. I wanted something integrated directly into the ST2 life cycle. So let me share my simple solution which works fairly well for my case. My solution is split up in two parts. We have Translation.js. A sencha class containing all my translations. And Localization.js doing the actual translation. "Translation.js" has a very simple structure. Basically it acts as a key-value map. All data is marked as static.
Ext.define('MyApp.util.Translations',{
 statics: {
  //list all translated languages
  available: ["EN", "DE"],
  data: {
  "login.label.notamember" : {
   "DE" :  "Kein Mitglied?",
   "EN" :  "Not a member?"
  },
  "checkin.error.nickname" : {
   "DE" :  "Der Spitzname muss zwischen {0} und {1} Zeichen lang sein.",
   "EN" :  "Alias must be between {0} and {1} characters."
  },
  
  //and so on ...
 }
});
Here comes the interesting part "Localization.js". Let me show you the code first and then I'll provide some explanation. Also ist is more or less self documenting.
Ext.define('MyApp.util.Localization', {
 //used as a shorthand
 alternateClassName: ['i10n'],
 requires: ['Ext.String','MyApp.util.Constants', 'MyApp.util.Translations', 'MyApp.util.Configuration'],
 singleton: true,
 config: {
  lang: null  
 },

 constructor: function() {
  //get browser/system locale 
  this.setLang(this.getLanguage());  
 },

 getTranslations: function() {
  return MyApp.util.Translations.data || {};
 },


 /**
 * @private
  * returns the browser language 
  * e.g. DE, EN
  */
 getLanguage: function() {
  var lang;
  //http://stackoverflow.com/questions/10642737/detecting-and-applying-current-system-language-on-html-5-app-on-android
     if (navigator && navigator.userAgent && (lang = navigator.userAgent.match(/android.*\W(\w\w)-(\w\w)\W/i))) {
         lang = lang[1];
     }

     if (!lang && navigator) {
         if (navigator.language) {
             lang = navigator.language;
         } else if (navigator.browserLanguage) {
             lang = navigator.browserLanguage;
         } else if (navigator.systemLanguage) {
             lang = navigator.systemLanguage;
         } else if (navigator.userLanguage) {
             lang = navigator.userLanguage;
         }
         lang = lang.substr(0, 2);
     }

     lang = lang.toUpperCase();

  console.log('browser language: '+lang);

  //check if this language is configured
  if(Ext.Array.indexOf(MyApp.util.Translations.available, lang) == -1) {
   console.log(lang + " not available using default " + appConfig.defaultLanguage);
   lang = appConfig.defaultLanguage;
  } else if(lang === 'undefined'|| lang.length == 0) {
   //use default language
   lang = appConfig.defaultLanguage;
  }

  //set language in configuration
  appConfig.language = lang;

  return lang;
 },

 /**
  * Translates the given key into the corresponding value in selected language.
  * @param key
  *   The key used to find a specific translation.
  *    if the translated string contains placeholders in form of {0}, {1} ... eiter
  *    1. additional parameters with replacing values 
  *    OR
  *    2. an array containing placeholders
  *    can be submited
  * @returns
  *   Translation or key if none was found
  */
  translate: function(key) {
   //alternativ with custom object and no sencha store
  var value = "",
   translations = this.getTranslations();
   if (key && translations[key] && translations[key][this.getLang()] && translations[key][this.getLang()] !== '') {
    value = translations[key][this.getLang()];
    if(arguments.length > 1) {
     //this is a string with placeholders
     //replace key with retrieved value and the call Ext.String.format     
     var _array;
     
     if(Object.prototype.toString.call(arguments[1]) === '[object Array]') {
      _array = new Array();
      _array[0] = value;
      for(var i = 0; i < arguments[1].length; i++) {
       _array[i+1] = arguments[1][i];
      }
     } else {
      arguments[0] = value;
      _array = arguments;
     }                     
     //Documentation for Ext.String.format http://docs.sencha.com/touch/2-0/#!/api/Ext.String-method-format
     //we need apply because we don't know the number of arguments
     value = Ext.String.format.apply(this, _array);
    }
   }
   return (value == "") ? key : value;
  },
});
We mark the class as a singleton and give it an alternate class name so we can easily call it from everywhere.
In the constructor we extract the system language and set in the lang config of our sencha app. If the system language is not translated we fall back to default language. To mark which languages have been translated simply add it to the available property in Translation.js.

The real "magic" ;) happen in translate.
 Translate takes a key and looks it up in your Translation.js. If no translation is found simply the value of key is returned so you can easily see parts of your application which are not translated.
Your translation can contain placeholders in form of {0}, {1}. To supply the placeholders you can pass them either as an array or as normal arguments. I'll rely on a build in Ext Method for the formatting of the string.

And you're done.

Now translating something in your app is as simple as:
  i10n.translate("checkin.error.nickname", 3, 25);

Freitag, 2. März 2012

Overwrite RestProxy in Sencha Touch 2

Here are the steps how you can override Sencha Touch functionalities. In this simple case I override the buildUrl method in Ext.data.proxy.Rest to customize the URL for my needs. Create a new class. There is no naming convention although I think it is useful to use the naming scheme from the class you are overriding. So in my case I'm using MyApp.data.proxy.CustomRestProxy. Instead of extend you'll then have to use override to specify the class whose functionality you want override.

Ext.define('MyApp.data.proxy.CustomRestProxy', {
 override: 'Ext.data.proxy.Rest',
 
   buildUrl: function(request) {
     //here I simply add an url prefix to all rest calls
         var  me = this, _serviceUrl = globalConf.serviceUrl, url = me.getUrl(request);
         request.setUrl(_serviceUrl + url);

         return me.callParent([request]);
     }
});
Put this class in a folder according to the name.
Mine is located in app/data/proxy/CustomRestProxy.js

 In your app.js make sure to set this class as required.
requires: ['MyApp.data.proxy.CustomRestProxy'] 


When you start your App and Sencha complains it can't find your new class you have to tell Sencha where to look.

Put
Ext.Loader.setPath('MyApp', 'app'); 
Before you call
Ext.application ...